/******************************************************************************
This file is part of AppKit.
Project: appkit
Author : FergusZeng
Email  : cblock@126.com
git	   : https://gitee.com/newgolo/appkit.git
*******************************************************************************
MIT License

Copyright (c) 2022 cblock@126.com

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/
#pragma once

#include <time.h>

#include <iostream>
#include <memory>
#include <string>
#include "appkit/basetype.h"

/**
 * @file datetime.h
 * @brief 日期时间
 */
namespace appkit {

/**
 * @class Time
 * @brief 时间类
 */
class Time {
public:
    Time(int sec, int us);
    explicit Time(uint64 us = 0);
    explicit Time(struct timeval tv);
    Time(const Time& time);
    virtual ~Time();
    /**
     * @brief 获取秒数
     * @return sint64
     */
    int sec() const;
    /**
     * @brief 获取微秒数
     * @return int
     */
    int usec() const;
    /**
     * @brief 转struct timeval
     * @return struct timeval 
     */
    struct timeval toTimeval() const;
    /**
     * @brief 时间转换成字符串
     * @return std::string
     */
    std::string toString();
    /**
     * @brief 转换成微秒数
     * @return uint64
     */
    uint64 toMicroSec();
    /**
     * @brief 当前时间(从1970-01-01 00:00:00 UTC开始)
     * @return Time
     */
    static Time fromEpoch();
    /**
     * @brief 当前时间(从系统开机的时刻算起)
     * @return Time
     * @note 系统运行时间:"cat /proc/uptime"
     */
    static Time fromMono();
    /**
     * @brief 获取时间间隔
     * @param monoStartTime 起始时间
     * @return uint64
     */
    static uint64 usSinceMono(const Time& monoStartTime);

    /**
     * @brief 当地时区与UTC时间的差(local_time-utc_time)
     * @return int
     */
    static int tzDiffSecs();

    /**
     * @brief 设置系统当前时间
     * @return bool 成功或失败
     */
    static bool setTime(const Time& utcTime, int tzMinute);

    Time& operator=(const Time& t);
    Time operator+(const Time& t);
    Time operator-(const Time& t);
    bool operator==(const Time& t) const;
    bool operator<(const Time& t) const;
    bool operator>(const Time& t) const;

private:
    int m_sec{0};
    int m_usec{0};
};

/**
 *  @class  DateTime
 *  @brief  日期时间结构体
 */
class DateTime {
    DECL_PROPERTY(uint32, 0, year, setYear)
    DECL_PROPERTY(uint32, 0, month, setMonth)
    DECL_PROPERTY(uint32, 0, day, setDay)
    DECL_PROPERTY(uint32, 0, hour, setHour)
    DECL_PROPERTY(uint32, 0, minute, setMinute)
    DECL_PROPERTY(uint32, 0, second, setSecond)
    DECL_PROPERTY(uint32, 0, msecond, setMSecond)

public:
    DateTime();
    explicit DateTime(const Time& epoch);
    DateTime(unsigned int year, unsigned int month, unsigned int day,
             unsigned int hour, unsigned int minute, unsigned int second);
    DateTime(const DateTime& copy);
    ~DateTime();
    Time toEpochTime();
    DateTime toUtcTime();
    uint32 weekday() const;
    /**
     * @brief 返回时区偏差的秒数(当前时区-UTC时间)
     * @return int
     */
    static int timeZone();
    /**
     * @brief 设置时区
     * @param tz 时区偏差的秒数(当前时区-UTC时间)
     */
    static void setTimeZone(const int& tz);
    /**
     * @brief 转换为字符串格式:"yyyy-mm-dd hh:MM:ss"
     * @return std::string
     */
    std::string toString();
    /**
     * @brief 判断是否是润年
     * @return true
     * @return false
     */
    bool isLeapYear();
    /**
     * @brief 获取当前日期时间
     * @return DateTime
     */
    static DateTime getDateTime();
    /**
     * @brief 设置当前时间
     * @param dateTime
     * @return true
     * @return false
     */
    static bool setDateTime(const DateTime& dateTime);
    /**
     * @brief 获取RTC时间
     * @return DateTime
     */
    static DateTime getRtcTime();
    /**
     * @brief 设置RTC时间
     * @param dateTime
     * @return true
     * @return false
     */
    static bool setRtcTime(const DateTime& dateTime);
    /**
     * @brief 重载等号
     * @param dt
     */
    bool operator==(const DateTime& dt) const;
    /**
     * @brief 重载赋值符
     * @param dt
     * @return DateTime&
     */
    DateTime& operator=(const DateTime& dt);
};

class Rate {
public:
    using Ptr = std::shared_ptr<Rate>;

public:
    explicit Rate(float frequency = 1);
    ~Rate();
    Rate(const Rate& rate);
    /**
     * @brief 复位
     * @param frequency 频率,大于0时有效,小于0时采用原来的设置
     */
    void reset(float frequency = -1.0f);
    /**
     * @brief 按frequency睡眠
     * @return true
     * @return false
     */
    bool sleep();
    /**
     * @brief 唤醒
     * @param sigma 提前唤醒时间允差(0.0~1.0)
     * @return bool 唤醒成功或失败
     */
    bool wakeup(float sigma = 0.0f);

private:
    Time m_start;
    uint64 m_usInterval;
};

}  // namespace appkit
